/*
 * Copyright (c) 2018-2999 湖南洛云网络科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 */

package com.yami.shop.live.comment.service.impl;

import cn.binarywang.wx.miniapp.bean.live.WxMaCreateRoomResult;
import cn.binarywang.wx.miniapp.bean.live.WxMaLiveResult;
import cn.binarywang.wx.miniapp.bean.live.WxMaLiveRoomInfo;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.constant.WxPayErrorCode;
import com.yami.shop.bean.enums.LiveInterfaceType;
import com.yami.shop.bean.param.LiveRoomParam;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.response.WxServerResponse;
import com.yami.shop.common.util.*;
import com.yami.shop.common.wx.WxInterfaceUtil;
import com.yami.shop.common.wx.bean.PageLiveRoomInfo;
import com.yami.shop.common.wx.bean.WxLiveRoomInfo;
import com.yami.shop.common.wx.bean.resp.RoomDetailResponse;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.config.WxConfig;
import com.yami.shop.live.comment.constant.LiveConstant;
import com.yami.shop.live.comment.dto.LiveRoomDto;
import com.yami.shop.live.comment.model.LiveLog;
import com.yami.shop.live.comment.model.LiveRoom;
import com.yami.shop.live.comment.dao.LiveRoomMapper;
import com.yami.shop.live.comment.service.LiveLogService;
import com.yami.shop.live.comment.service.LiveRoomService;
import com.yami.shop.live.comment.util.WxImageUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 *
 *
 * @author lhd
 * @date 2020-08-05 08:53:17
 */
@Service
@AllArgsConstructor
@Slf4j
public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomMapper, LiveRoom> implements LiveRoomService {

    /**
     * 一页的数量
     */
    private static final Long MAX_PAGE_NUM = 80L;
    private final LiveRoomMapper liveRoomMapper;
    private final WxConfig wxConfig;
    private final ShopConfig shopConfig;
    private final WxImageUtil wxImageUtil;
    private final LiveLogService liveLogService;
    private final MapperFacade mapperFacade;
    private final WxInterfaceUtil wxUtil;

    public static void main(String[] args) {
        DateTime startTime = new DateTime("2021-05-08 10:17:00", DatePattern.NORM_DATETIME_PATTERN);
        DateTime endTime = new DateTime("2021-05-09 11:18:00", DatePattern.NORM_DATETIME_PATTERN);
        System.out.println(DateUtil.isIn(endTime,startTime,DateUtil.offsetMinute(startTime,30)));
        System.out.println(DateUtil.isIn(endTime,startTime,DateUtil.offsetHour(startTime,24)));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveLiveRoom(LiveRoom liveRoom) throws WxErrorException {
        // 1.校验今日可用次数并保存or修改商家次数记录
        liveLogService.checkNumsAndSaveLog(liveRoom.getShopId(), LiveInterfaceType.CREATE_ROOM, "创建直播间");

        // 校验时间,开始时间需要在当前时间的10分钟后 并且开始时间不能在6个月后,
        // 开始时间和结束时间间隔不得短于30分钟，不得超过24小时
        Date startTime = liveRoom.getStartTime();
        Date endTime = liveRoom.getEndTime();
        // 1. 开始时间是否在当前时间和十分钟内的时间内，如果为true则表示错误，抛出异常
        // 2. 开始时间是否在当前时间和六个月的时间内，如果为false则表示错误，抛出异常
        boolean expired = DateUtil.isIn(startTime,new Date(),DateUtil.offsetMinute(new Date(),10)) ||
                !DateUtil.isIn(startTime,new Date(),DateUtil.offsetMonth(new Date(),6));
        // 开始时间和结束时间间隔不得短于30分钟，不得超过24小时
        // 1. 结束时间是否和起始时间间隔不得短于30分钟，如果为true则表示错误，抛出异常
        // 2. 结束时间是否在起始时间开始后的24小时的时间内，如果为false则表示错误，抛出异常
        boolean expiredEndTime = DateUtil.isIn(endTime,startTime,DateUtil.offsetMinute(startTime,30)) ||
                !DateUtil.isIn(endTime,startTime,DateUtil.offsetHour(startTime,24));

        if(DateUtil.compare(startTime,endTime) > 0){
            // 开始时间不能大于结束时间
            throw new YamiShopBindException("yami.live.time.check");
        }
        if(expired){
            // 开始时间需要在当前时间的10分钟后,并且不能在6个月后
            throw new YamiShopBindException("yami.live.time.one.check");
        }
        if(expiredEndTime){
            // 开始时间和结束时间间隔不得短于30分钟，不得超过24小时
            throw new YamiShopBindException("yami.live.time.two.check");
        }
        // 校验图片
        this.checkImg(liveRoom);
         // 1.将背景图，封面图，分享图添加到微信临时素材
        // 发起微信审核, 先获取微信的media_id
        String coverMediaId = wxImageUtil.wxImageUpload(shopConfig.getDomain().getResourcesDomainName() + "/" + liveRoom.getCoverImg());
        String feedsImgMediaId = wxImageUtil.wxImageUpload(shopConfig.getDomain().getResourcesDomainName() + "/" + liveRoom.getFeedsImg());
        String shareImgMediaId = wxImageUtil.wxImageUpload(shopConfig.getDomain().getResourcesDomainName() + "/" + liveRoom.getShareImg());
        liveRoom.setCoverImgId(coverMediaId);
        liveRoom.setShareImgId(shareImgMediaId);
        liveRoom.setFeedsImgId(feedsImgMediaId);
        LiveRoom.RoomToolsVO roomToolsVo = liveRoom.getRoomToolsVo();
        // 2.调用微信添加直播间接口添加直播间
        WxMaLiveRoomInfo roomInfo = mapperFacade.map(liveRoom, WxMaLiveRoomInfo.class);
        roomInfo.setStartTime(liveRoom.getStartTime().getTime() / 1000);
        roomInfo.setEndTime(liveRoom.getEndTime().getTime() / 1000);
        roomInfo.setFeedsImg(feedsImgMediaId);
        // 设置微信直播间功能设置信息
        roomInfo.setCloseShare(roomToolsVo.getCloseShare());
        roomInfo.setCloseKf(roomToolsVo.getCloseKf());
        roomInfo.setCloseReplay(roomToolsVo.getCloseReplay());
        roomInfo.setCloseComment(roomToolsVo.getCloseComment());
        roomInfo.setCloseGoods(roomToolsVo.getCloseGoods());
        roomInfo.setCloseLike(roomToolsVo.getCloseLike());
        roomInfo.setCoverImg(liveRoom.getCoverImgId());
        roomInfo.setShareImg(liveRoom.getShareImgId());
        try {
            WxMaCreateRoomResult wxMaCreateRoomResult = wxConfig.getWxMaService().getLiveService().createRoom(roomInfo);
            // 4.保存直播间信息到数据库
            liveRoom.setRoomTools(Json.toJsonString(liveRoom.getRoomToolsVo()));
            liveRoom.setRoomId(wxMaCreateRoomResult.getRoomId());
            save(liveRoom);
        }catch (WxErrorException e){
            if(Objects.equals(e.getError().getErrorCode(), LiveConstant.WECHAT_NAME_LENGTH_ERROR)){
                // 名称长度不符合规则！
                throw new YamiShopBindException("yami.live.name.check");
            }
            if(Objects.equals(e.getError().getErrorCode(), LiveConstant.WECHAT_CHECK)){
                // 主播微信号未实名认证
                throw new YamiShopBindException("yami.live.user.name.check");
            }
             if(!Objects.equals(e.getError().getErrorCode(),0)){
                // 创建失败，请仔细检查直播间的配置
                throw new YamiShopBindException("yami.live.config.check");
            }
        }
    }


    /**
     * 定时每分钟去同步微信的直播间接口
     * @throws WxErrorException 微信异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void synchronousWxLiveRoom() throws WxErrorException{
        // 首先校验商家今日可用次数
        LiveLog liveLogDb = liveLogService.getOne(new LambdaQueryWrapper<LiveLog>()
                .eq(LiveLog::getShopId, Constant.PLATFORM_SHOP_ID)
                .eq(LiveLog::getType, LiveInterfaceType.ROOM_LIST.value())
                .le(LiveLog::getCreateTime, DateUtil.endOfDay(new Date()))
                .ge(LiveLog::getCreateTime,DateUtil.beginOfDay(new Date())));
        // 如果次数大于上限则取消继续
        if(Objects.nonNull(liveLogDb) && liveLogDb.getNum() > LiveInterfaceType.ROOM_LIST.getNumLimit()){
            // 平台今日可用获取直播间信息的次数已达上限！
            log.info("yami.live.platform.numLimit");
            return;
        }

        List<WxMaLiveResult.RoomInfo> liveInfos;
        try {
            liveInfos = wxConfig.getWxMaService().getLiveService().getLiveInfos();
        }catch (Exception e){
            log.error("同步直播间信息失败！");
            log.error(e.getMessage());
            return;
        }
        if(CollectionUtils.isEmpty(liveInfos)){
            return;
        }
        Integer total = liveInfos.size();
        // 批量修改
        liveRoomMapper.updateBatchByRoomId(liveInfos);
        int pages = (int)Math.ceil(Arith.div(total,MAX_PAGE_NUM));
        // 4.保存or修改商家次数记录
        if(Objects.isNull(liveLogDb)){
            LiveLog liveLog = new LiveLog();
            liveLog.setCreateTime(new Date());
            liveLog.setNum(1);
            liveLog.setShopId(Constant.PLATFORM_SHOP_ID);
            liveLog.setType(LiveInterfaceType.ROOM_LIST.value());
            liveLogService.save(liveLog);
        }else{
            liveLogDb.setNum(liveLogDb.getNum() + pages);
            liveLogService.updateById(liveLogDb);
        }
    }

    @Override
    public List<LiveRoomParam> getLivingRoomByProdId(Long prodId) {
        return liveRoomMapper.getLivingRoomByProdId(prodId);
    }

    @Override
    public IPage<LiveRoomDto> pageRoomAndDetail(PageParam<LiveRoomDto> page, LiveRoomParam liveRoom) {
        page.setRecords(liveRoomMapper.pageRoomAndDetail(new PageAdapter(page),liveRoom));
        page.setTotal(liveRoomMapper.countRoomAndDetail(liveRoom));
        return page;
    }

    /**
     * 读取微信直播间列表
     * @param start 从start行开始读取
     * @throws WxErrorException 微信异常
     */
    private WxServerResponse<List<RoomDetailResponse>> getLiveRoomList(Long start)  throws WxErrorException{
        String accessToken = wxConfig.getWxMaService().getAccessToken();
        PageLiveRoomInfo wxLiveRoomInfo = new PageLiveRoomInfo();
        wxLiveRoomInfo.setStart(start);
        wxLiveRoomInfo.setLimit(MAX_PAGE_NUM);
        wxLiveRoomInfo.setAccessToken(accessToken);
        return wxUtil.pageLiveRoom(wxLiveRoomInfo);
    }

    /**
     * 核验直播间图片信息
     * @param liveRoom
     */
    private void checkImg(LiveRoom liveRoom) {
        if(Objects.equals(ImageUtil.imgUrlFileType(liveRoom.getCoverImg()), LiveConstant.WEBP) ||
            Objects.equals(ImageUtil.imgUrlFileType(liveRoom.getFeedsImg()), LiveConstant.WEBP) ||
            Objects.equals(ImageUtil.imgUrlFileType(liveRoom.getShareImg()), LiveConstant.WEBP)) {
            throw new YamiShopBindException("yami.live.img.isWebp");
        }
    }
}
